package cn.org.xwb.common.file.service.impl;

import cn.org.xwb.common.file.dto.FileSliceUploadDto;
import cn.org.xwb.common.file.service.FileUploadService;
import cn.org.xwb.common.file.utils.FileUploadUtil;
import cn.org.xwb.common.file.utils.FileUtil;
import cn.org.xwb.common.file.utils.MinioUtil;
import cn.org.xwb.common.model.vo.RespResult;
import io.minio.messages.Item;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;

@Service
@Log4j2
public class FileUploadServiceImpl implements FileUploadService {

    @Autowired
    private MinioUtil minioUtil;

    @Autowired
    private FileUploadUtil fileUploadUtil;

    /**
     * 获取要上传文件的下一个上传分片索引
     *
     * @param bucketName   桶
     * @param fileName     文件名
     * @param fileType     文件类型
     * @param md5          文件 md5
     * @param tempDirName  文件分片所在的目录名（只是分片文件父目录名称而已）
     * @param fileSliceLen 文件分片个数
     * @return
     */
    @Override
    public RespResult<Object> getNextFileSliceIdx(
            String bucketName,
            String fileName, String fileType, String md5, String tempDirName, Integer fileSliceLen
    ) {
        // 获取文件后缀
        String extension = FileUtil.getExtensionByFilename(fileName);
        if (Objects.isNull(extension) || extension.isEmpty()) {
            extension = FileUtil.getExtensionByMimeType(fileType);
        }
        String minioFilename = md5 + "/" + md5 + extension;
        // 文件存在
        if (minioUtil.fileIsExists(bucketName, minioFilename)) {
            // 获取文件在线访问地址
            String fileUrl = fileUploadUtil.getFileUrl(bucketName, minioFilename);
            return RespResult.success("文件上传成功", fileUploadUtil.genFileSliceUploadSuccessResultVo(fileUrl));
        }
        String chunkDirName = md5 + "/" + tempDirName + "/";
        // 存储分片的文件夹不存在
        if (!minioUtil.folderIsExist(bucketName, chunkDirName)) {
            return RespResult.success("文件开始上传", fileUploadUtil.genFileSliceUploadStartResultVo());
        }
        // 获取要上传文件的下一个上传分片索引
        List<Item> objs = minioUtil.getObjs(bucketName, chunkDirName, false);
        objs.sort((o1, o2) -> {
            return Integer.valueOf(o1.objectName().substring(o1.objectName().lastIndexOf("/") + 1)) -
                    Integer.valueOf(o2.objectName().substring(o2.objectName().lastIndexOf("/") + 1));
        });
        // 最后一个分片在 minio 中的对象名
        String lastObjName = objs.get(objs.size() - 1).objectName();
        // 下一个分片索引
        Integer nextChunkIdx = Integer.valueOf(lastObjName.substring(lastObjName.lastIndexOf("/") + 1)) + 1;
        // 上传完成但未合并
        if (nextChunkIdx >= fileSliceLen) {
            // 合并文件
            chunkDirName = md5 + "/" + tempDirName;
            // 失败了
            if (!fileUploadUtil.chunkMergeAndClear(bucketName, chunkDirName, md5, minioFilename)) {
                return RespResult.fail("文件上传失败", fileUploadUtil.genFileSliceUploadFailResultVo());
            }
            // 获取文件在线访问地址
            String fileUrl = fileUploadUtil.getFileUrl(bucketName, minioFilename);
            return RespResult.success("文件上传成功", fileUploadUtil.genFileSliceUploadSuccessResultVo(fileUrl));
        }
        return RespResult.success("文件上传中...", fileUploadUtil.genFileSliceUploadUploadingResultVo(nextChunkIdx));
    }

    /**
     * 文件分片上传
     *
     * @param fileSliceUploadDto
     * @return
     */
    @Override
    public RespResult<Object> fileSliceUpload(FileSliceUploadDto fileSliceUploadDto) {
        // 分片缓存
        minioUtil.addFileToMinio(
                fileSliceUploadDto.getBucket(),
                fileSliceUploadDto.getObjName(),
                fileSliceUploadDto.getChunk(),
                fileSliceUploadDto.getMimeType()
        );
        // 倒数第二片上传完成
        if (fileSliceUploadDto.getChunkIdx() + 2 == fileSliceUploadDto.getChunkTotal()) {
            return RespResult.success("文件上传完成", fileUploadUtil.genFileSliceUploadUploadedResultVo(fileSliceUploadDto.getChunkIdx() + 1));
        }
        // 当前上传的为最后一片，分片合并，清除分片缓存
        if (fileSliceUploadDto.getChunkIdx() + 1 == fileSliceUploadDto.getChunkTotal()) {
            // 失败了
            if (!fileUploadUtil.chunkMergeAndClear(fileSliceUploadDto)) {
                return RespResult.fail("文件上传失败", fileUploadUtil.genFileSliceUploadFailResultVo());
            }
            // 文件全部上传完成
            // 获取文件在线访问地址
            String fileUrl = fileUploadUtil.getFileUrl(fileSliceUploadDto);
            log.info("文件 {} 上传成功，文件访问地址：{}", fileSliceUploadDto.getFilename(), fileUrl);
            return RespResult.success("文件上传成功", fileUploadUtil.genFileSliceUploadSuccessResultVo(fileUrl));
        }
        return RespResult.success("文件上传中...", fileUploadUtil.genFileSliceUploadUploadingResultVo(fileSliceUploadDto.getChunkIdx() + 1));
    }


}
